class RPN:
    """
    Class Representation of a Reverse Polish Notation Calculator

    Attributes:
    	numstack (list): Operands available in the memory of the calculator. Works as a stack, last 2 values are always
    		used when performing operations.
    """
    def __init__(self):
        self.numstack=[]

    def clear(self):
        """
        Resets calculator to an empty stack
        :return: None
        """
        self.numstack.clear()

    def next(self, op):
        """
        Takes the next value, either an operator or operand, and modifies the number stack accordingly
        :param op: next input to the calculator
        :return: value of op if op is an operand, result of calculation if op is an operator
        """
        if op in RPN.operators.keys():          # if op is available operation and enough operands, perform operation
            if len(self.numstack) < 2:
                raise ArithmeticError("Invalid operation, not enough operands in stack.")
            return RPN.operators[op](self)
        else:                                   # if op is float, add to stack
            try:
                op = float(op)
            except ValueError:
                raise ValueError("Given value must be a valid operator " + str(list(RPN.operators.keys())) +
                                " or a real number.")

            self.numstack.append(float(op))
            return op

    def add(self):
        """
        Performs add on last 2 operands, then replaces said operands in the stack w/ the result
        :return: result of add operation on last two values in the stack
        """
        result = self.numstack.pop() + self.numstack.pop()

        self.numstack.append(result)
        return result

    def multiply(self):
        """
        Performs multiply on last 2 operands, then replaces said operands in the stack w/ the result
        :return: result of multiply operation on last two values in the stack
        """
        result = self.numstack.pop() * self.numstack.pop()

        self.numstack.append(result)
        return result

    def divide(self):
        """
        Performs divide on last 2 operands, then replaces said operands in the stack w/ the result

        Division is done "2nd-to-last / last" to follow RPN rules
        :return: result of divide operation on last two values in the stack
        """
        result = self.numstack.pop(len(self.numstack)-2) / self.numstack.pop()

        self.numstack.append(result)
        return result

    def subtract(self):
        """
        Performs subtract on last 2 operands, then replaces said operands in the stack w/ the result

        Subtraction is done "2nd-to-last - last" to follow RPN rules
        :return: result of subtract operation on last two values in the stack
        """
        result = self.numstack.pop(len(self.numstack)-2) - self.numstack.pop()

        self.numstack.append(result)
        return result

    # class var, used to pair operator symbols (key) to corresponding methods (value)
    operators = {
        '+': add,
        '*': multiply,
        '/': divide,
        '-': subtract
    }
